{% extends "tutorial.html" %}
{% load mixin from templatefilters %}

{% block pagebreadcrumb %}{{ tut.title }}{% endblock %}

{% block head %}
<style>
.talkinghead:before{
  background-image:url();
  background-position:0px 0px!important;
}
.talkinghead-everyone:before {
  background-image:url();
  background-position:0px 0px!important;
}
.talkinghead-pk:before {
  background-image:url(/static/images/profiles/paulkinlan.png);
  background-size: 60px 60px;
  background-position:0px 0px!important;
}

pre.inline {
  display: inline;
}
</style>


{% endblock %}

{% block iscompatible %}
  return !!Modernizr.___COMPAT_TEST___
{% endblock %}

{% block html5badge %}
<!-- Your HTML5 badge (tech class icons used in the article) goes here -->
{% endblock %}

{% block translator %}
<div class="translator">
  <strong>Translator:</strong> <a href="http://cwdoh.github.io">도창욱 (Chang W. Doh)</a>
</div>
{% endblock %}

{% block content %}

<h2 id="toc-introduction">모바일에서 놀라운 풀스크린 환경 구축하기</h2>

<blockquote class="commentary talkinghead talkinghead-everyone">
언제나 많은 사람들이 얘기합니다.<br/>
"네이티브 앱의 가장 좋은 것 중 하나는 그들이 풀스크린이라는 점이다."
</blockquote>

<blockquote class="commentary talkinghead talkinghead-pk" id="compressors">
일반적인 관점에서 볼 때 저를 짜증나게 하는 것이 있습니다. 네, 웹페이지가 풀스크린이 아니라는 것이죠. 주소창과 보통 몇 가지의 또다른 네비게이션 컨트롤들이 있기 때문입니다. 그러나 많은 모던 브라우저들은 꽤 빠른 속도로 (이러한) 쓸모없는 것들을 버리는데 많이 익숙해졌습니다.
</blockquote>

<p>우리는 실감적인 풀스크린 웹사이트와 어플리케이션을 쉽게 만들 수 있는 능력이 있지만 웹의 그 어느 것과 마찬가지로 그를 위한 몇가지 방법이 필요합니다. 더 많은 브라우저들이 풀스크린을 지원하는 "설치된 웹 앱" 환경을 지원하고 있는 것은 현재 시점에서 더더욱 중요합니다.

  </p>

<figure>
<iframe width="324" height="576" src="//www.youtube.com/embed/ZRqr5x73-ng" frameborder="0" allowfullscreen></iframe>
<figcaption>안드로이드 크롬에서 풀스크린을 지원하는 사이트의 예
  </figcaption>
</figure>
<h2 id="toc-getting">앱이나 사이트를 풀스크린으로 만나보세요.</h2>

<p>사용자나 개발자가 웹 앱에 풀스크린을 적용하는데는 여러가지 방법이 있습니다.
  </p>
<ul>
  <li>속임수 : 주소창을 자동으로 감추기</li>
  <li>사용자의 제스처를 받아 브라우저에 풀스크린 실행을 요청하기</li>
  <li>홈스크린으로 앱을 설치하기</li>
</ul>

<h3 id="toc-faking">속임수 : 주소창을 자동으로 감추기
  </h3>
<p>다음과 같이 주소창을 자동으로 감추는 "풀스크린 속임수"를 쓸 수 있습니다.
  </p>
<pre class="prettyprint">window.scrollTo(0,1);</pre>

<blockquote class="commentary talkinghead talkinghead-pk">
편하게 얘기하겠습니다. 그 방법은 분명 존재하고 가능한 것이지만 핵(hack)입니다. 제발 쓰지마세요.
</blockquote>

<p>페이지가 로딩되면 브라우저 막대를 저리 사라지라고 하는 꽤 간단한 방법입니다. 불행하게도 이것은 표준도 아닐 뿐더러 잘 지원되는 것도 아닙니다. 여러분은 또 다시 갖가지 희안한 것에 둘러쌓여 일하게 될 것입니다. 예를 들어 사용자가 뒤로가기를 했을 때 페이지의 위치를 종종 복구합니니다. <pre class="inline">windo.scrollTo</pre> 사용은 이것을 막아버려 사용자를 짜증나게 합니다. 이 방법으로 작업을 하려면 로컬 스토리지에 최종 위치를 저장해야만 할 것이고 (예를 들어 사용자가 다중 윈도우에서 페이지를 여는 경우와 같은) 치명적인 경우들을 다루어야 할 것입니다.

  </p>

<h3 id="toc-request">사용자의 제스처를 받아 브라우저에 풀스크린 실행을 요청하기
  </h3

<p><a href="http://caniuse.com/#feat=fullscreen">모든 플랫폼이 전부 똑같은 것은 아닙니다.</a> iOS 사파리는 풀스크린 API가 없지만 크롬 안드로이드와 파이어폭스는 있습니다.</p>
<p>대부분의 어플리케이션들은 풀스크린 규격에서 제공하는 자바스크립트 API와 CSS Selector의 조합을 이용하여 구축할 수 있습니다.</p>

<p>풀스크린 환경을 구축할 때 다루어야 할 주요 자바스크립트 API들:</p>

<ul>
  <li><pre class="inline"><i>element</i>.requestFullscreen()</pre> (현재 크롬과 파이어폭스는 접두사가 필요)</li>
  <li><pre class="inline">document.cancelFullscreen()</pre> (현재 크롬과 파이어폭스는 접두사가 필요)</li>
  <li><pre class="inline">document.fullscreenElement()</pre> (현재 크롬과 파이어폭스는 접두사가 필요)</li>
</ul>

<blockquote class="commentary talkinghead talkinghead-pk">
screen에서 'S'의 대소문에 대해 prefix 버전들이 아직 많은 불안정함이 있는 것에 주의해야합니다. 그러나 이것은 규격의 진행 중에 생긴 문제일 뿐입니다.
<br/><br/>
역주: 규격 상의 API는 "requestFullscreen"이지만, 현재 크롬과 파이어폭스에서는 "Fullscreen"와 "FullScreen"처럼 'S'에 대하여 대소문자가 다릅니다. 많이 혼동할 수 있는 부분이니 당분간 사용 시에 주의가 필요합니다.
</blockquote>

<p>크롬은 앱이 풀스크린 상태에 있을 때 브라우저의 UI 컨트롤이 보이지 않도록 준비되어 있습니다. 이것은 사용자들이 여러분의 환경과 상호작용하는 방식을 바꾸었습니다. 이 앱들은 앞으로 가기나 뒤로 가기 같은 표준 네비게이션 컨트롤들을 가지고 있지 않습니다. 대신 새로고침 버튼과 같은 탈출구를 가지고 있습니다. 이것은 이와 같은 시나리오를 맞추기 위해 중요합니다. 여러분은 브라우저가 풀스크린 모드에 진입했을 때 스타일과 사이트의 표현 형태를 변경하는데 도움을 주는 몇 가지 CSS 셀렉터를 사용할 수 있습니다.</p>

<pre class="prettyprint">&lt;button id="goFS">Go fullscreen&lt;button>
&lt;script>
   var goFS = document.getElementById("goFS");
   goFS.addEventListener("click", function() {
      document.body.requestFullScreen();
   }, false);
&lt;/script></pre>

<p>위의 예제는 (webkit과 같은) vendor prefix의 사용으로 인한 복잡도를 숨겨두었으므로 약간 부자연스럽습니다.</p>

<blockquote class="commentary talkinghead talkinghead-pk">
젠장할 vendor prefix!
</blockquote>

<p>실제 코드는 훨씬 더 복잡합니다. 풀스크린을 전환하는데 사용할 수 있는 <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode">모질라가 만든</a> 아주 유용한 스크립트가 있으니 참고하시기 바랍니다. 보시다시피 규격화된 API의 비교에서처럼 vendor prefix 상황으로 인해 더 복잡하고 다루기가 힘듭니다.  아래와 같이 꽤 단순화된 코드조차 여전히 복잡합니다.</p>

<pre class="prettyprint">function toggleFullScreen() {
  var doc = window.document;
  var docEl = doc.documentElement;

  var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen;
  var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen;

  if(!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement) {
    requestFullScreen.call(docEl);
  }
  else {
    cancelFullScreen.call(doc);
  }
}</pre>

<p>우리 웹 개발자들은 복잡한 것을 싫어합니다. 두 개의 제법 다른 자바스크립트 API와 vendor prefix를 하나의 견고한 API로 통합한 <a href="http://sindresorhus.com/screenfull.js"/>Sindre Sorhus'</a>과 <a href="https://github.com/sindresorhus/screenfull.js">Screenfull.js</a>는 훌륭하게 추상화된 고수준 API입니다.</p>

<h3 id="toc-launch">풀스크린 페이지 런칭하기</h3>

<p>사용자가 네비게이션을 할 때 풀스크린 웹 페이지의 런칭은 불가능합니다. 풀스크린 모드로 진입 시에는 사용자 제스쳐가 요구되어 모든 페이지 로딩 시 아주 짜증을 유발하기 때문에 브라우저 업체들은 풀스크린 환경을 지원하는 것이 매우 성가신 편입니다. 브라우저 업체들이 앱을 "설치"할 수 있도록 하고 있지만 실제 설치 동작은 사용자가 앱을 플랫폼에서 실행하는 것을 원한다는 것을 운영체제로 전달하는 (일종의) 신호입니다.</p>

<p>메이저 모바일 플랫폼들 간에 다음과 같이 메타 태그나 메니페스트 파일들의 사용을 구현하는 것은 꽤 쉬운 일입니다.</p>

<h4>iOS</h4>
<p>이미 아이폰에서 실행할 때도 사용자들은 웹앱을 홈스크린으로 설치하고 그것들을 풀스크린 웹 앱처럼 실행하는 것이 가능합니다.</p>

<pre class="prettyprint">&lt;meta name="apple-mobile-web-app-capable" content="yes"></pre>

<p><a href="https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html">From Apple</a>:</p>
<blockquote>만약 컨텐츠가 yes로 설정되어 있으면 웹 어플리케이션은 풀스크린 모드로 동작하며 반대라면 그렇지 않습니다. 기본 동작은 웹 컨텐츠를 사파리에서 실행하는 것입니다. 읽기 전용 자바스크립트 속성인 window.navigator.standalone를 사용하여 웹페이지가 풀스크린 모드로 동작 중인지를 확인할 수 있습니다.
</blockquote>

<h4>크롬 안드로이드</h4>
<p>크롬팀은 사용자가 앱을 홈스크린에 추가했을 때 페이지를 풀스크린 모드로 실행하는지를 브라우저에 알려주는 기능을 최근 구현했습니다. 이 기능은 iOS 사파리와 유사합니다.</p>

<pre class="prettyprint">&lt;meta name="mobile-web-app-capable" content="yes"></pre>

<p><a href="https://developers.google.com/chrome/mobile/docs/installtohomescreen">From Chrome</a>:</p>
<blockquote>여러분은 디바이스의 홈스크린에 추가할 어플리케이션 단축 아이콘과 안드로이드용 크롬의 "홈스크린에 추가(Add to homescreen)" 메뉴 항목을 사용하여 앱이 풀스크린으로 실행되는 "앱 모드"를 가진 웹 앱을 구성할 수 있습니다.</blockquote>

<h4>파이어폭스 OS</h4>
<p>파이어폭스 OS는 휴대폰을 위한 앱을 생성하기 위해 개발자를 위한 설치 가능한 웹 앱과 패키지된 앱 모델을 구현하였습니다. 이 모델은 약간 더 복잡하지만 더 설치 가능한 앱들의 더 폭넓은 전략에 적합합니다. 개발자는 파이어폭스 OS가 설치 시 파싱할 앱 매니페스트를 정의해야 합니다.</p>

<p><a href="https://developer.mozilla.org/en-US/Apps/Developing/Manifest#fullscreen">From Mozilla</a>:</p>
<pre class="prettyprint">{
  "name": "My App",
  "description": "My elevator pitch goes here",
  "launch_path": "/",
  "icons": {
    "128": "/img/icon-128.png"
  },
  <b>"fullscreen": true</b>
}</pre>

<blockquote class="commentary talkinghead talkinghead-pk">
만약 "설치된 앱"과 같은 느낌을 원한다면 여러분이 사용해야할 방법들로 "설치" API들이 있습니다. 이들은 한동안 순수한 웹 콘텐츠보다 OS와 훨씬 더 밀접하게 통합될 것이며 매끄러운 풀스크린 전환을 할 수 있도록 합니다.
</blockquote>

<h2 id="toc-apitips">API 팁들</h2>

<h3 id="toc-documentfullscreen">문서를 풀스크린으로 만들기</h3>
<p>body 엘리먼트가 풀스크린 모드를 가지고 있다고 생각하는 것은 자연스럽지만, 만약 웹킷이나 블링크 기반의 렌더링 엔진을 사용하고 있다면 body 폭이 모든 내용을 다 포함할 수 있는 가능한한 최소의 사이즈로 줄어드는 특이한 현상을 가지고 있는 것을 아마 볼 수 있을 것입니다.</p>

<figure>
<img src="/static/images/mobile/fullscreen/body.png" style="width:300px;">
<figcaption>Figure 1: body 엘리먼트의 풀스크린 모드.</figcaption>
</figure>

<p>이를 수정하기 위해서는 body 엘리먼트 대신 document 엘리먼트를 사용해야 합니다.</p>

<pre class="prettyprint">document.documentElement.requestFullScreen();</pre>

<figure>
<img src="/static/images/mobile/fullscreen/document.png" style="width:300px;">
<figcaption>Figure 2: document 엘리먼트의 풀스크린 모드.</figcaption>
</figure>

<h3 id="toc-videofullscreen">비디오 엘리먼트를 풀스크린 모드로 만들기</h3>
<p>비디오 엘리먼트를 풀스크린 모드로 만들기는 다른 모든 엘리먼트를 풀스크린으로 만드는 것과 완전히 똑같습니다. 비디오 엘리먼트에서 <pre class="inline">requestFullScreen</pre> 메소드를 호출하세요.</p>
<pre class="prettyprint">&lt;video id=videoElement>&lt;/video>
&lt;button id="goFS">Go Fullscreen&lt;/button>
&lt;script>
   var goFS = document.getElementById("goFS");
   goFS.addEventListener("click", function() {
      var videoElement = document.getElementById("videoElement");
      videoElement.requestFullScreen();
   }, false);
&lt;/script></pre>

<p>만약 &lt;video&gt;가 controls 속성 정의를 가지고 있지 않다면, 사용자는 일단 풀스크린 모드에 들어가면 컨트롤할 수 있는 방법이 없습니다. 이를 처리하기 위해 권장되는 방법은 비디오와 사용자에게 보여주기를 원하는 컨트롤들을 감싸는 기본 컨테이너를 가지는 것입니다.</p>

<pre class="prettyprint">&lt;div id="container">
  &lt;video>&lt;video>
  &lt;div>
    &lt;button>Play&lt;button>
    &lt;button>Stop&lt;button>
    &lt;button id="goFS">Go fullscreen&lt;button>
  &lt;div>
&lt;div>
&lt;script>
   var goFS = document.getElementById("goFS");
   goFS.addEventListener("click", function() {
      var container = document.getElementById("container");
      container.requestFullScreen();
   }, false);
&lt;script></pre>

<p>(예를 들어 "goFS" 버튼을 감추기 위한) CSS pseudo 셀렉터를 컨테이너 객체와 결합할 수 있으므로 이는 여러분에게 아주 커다란 유연성을 제공합니다.</p>

<pre class="prettyprint">&lt;style>
#goFS:full-screen #goFS {
  display: none;
}
#goFS:-webkit-full-screen #goFS {
  display: none;
}
#goFS:-moz-full-screen #goFS {
  display: none;
}
&lt;style></pre>

<p>이러한 패턴의 사용을 통해 풀스크린 모드로 동작하는 중인지를 검출할 수 있으며 적합한 사용자 인터페이스를 다음과 같이 적용할 수 있습니다.</p>

<ul>
  <li>시작 페이지로 되돌아가기 위한 링크의 제공
    </li>
  <li>다이얼로그를 닫거나 뒤로 돌아가기 위한 메커니즘의 제공
    </li>
</ul>

<h2 id="toc-uxguidelines">UI 지침들</h2>

<h3 id="toc-dontrely">네비게이션 컨트롤에 의존하지 마세요</h3>
<p>iOS나 파이어폭스 OS는 하드웨어적인 뒤로 가기 버튼이나 새로고침 제스처를 가지고 있지 않으므로 사용자가 잠김 없이 앱을 네비션이션할 수 있도록 열어두어야 합니다.</p>

<p>만약 풀스크린 모드나 설치 모드에서 실행 중이라면 쉽게 모든 주 플랫폼들에서 이를 검출할 수 있습니다.</p>

<h4>iOS</h4>
<pre class="prettyprint">if(window.navigator.standalone == true) {
  // 앱이 설치되어 풀스크린 모드로 동작함

}</pre>

<h4>크롬 안드로이드</h4>
<p>설치된 앱과 같은 앱이 실행되었을 때, 크롬은 진짜 풀스크린 환경을 실행하지 않으므로 <pre class="inline">document.fullscreenElement</pre>는 null을 반환하고 CSS Selector는 동작하지 않습니다. 크롬은 또한 iOS의 navigator.standalone 속성에 대한 API와 호환되지 않습니다.</p>

<p>만약 사용자가 사이트에서 제스쳐를 통한 풀스크린을 요청하였을 경우 UI가 다음과 같은 풀스크린 상태에 반응하기 위해 적용한 CSS pseudo 셀렉터를 포함하여 표준 풀스크린 API를 사용할 수 있습니다.</p>

<pre class="prettyprint">selector:-webkit-full-screen {
  display: block; // 풀스크린 모드일 때만 엘리먼트를 표시합니다.
}

selector {
  display: none; // 풀스크린모드가 아닐 때 엘리먼트를 숨깁니다.
}</pre>

<h4>파이어폭스</h4>
<p>사용자가 사이트를 통해 풀스크린 모드를 요청하거나 풀스크린 모드에서 앱을 실행하였을 때 UI가 다음과 같은 풀스크린 상태에 반응하기 위해 적용한 CSS pseudo 셀렉터를 포함하여 표준 풀스크린 API를 사용할 수 있습니다.
  </p>

<pre class="prettyprint">selector:-moz-full-screen {
  display: block; // 풀스크린 모드일 때만 엘리먼트를 표시합니다.
}

selector {
  display: none; // 풀스크린모드가 아닐 때 엘리먼트를 숨깁니다.
}</pre>

<h4>규격</h4>
<p>규격에서의 철자는 크롬과 파이어폭스의 구현과는 약간 차이가 있습니다만 기능적으로는 동일합니다.</p>

<pre class="prettyprint">selector:fullscreen {
  display: block; // 풀스크린 모드일 때만 엘리먼트를 표시합니다.
}

selector {
  display: none; // 풀스크린모드가 아닐 때 엘리먼트를 숨깁니다.
}</pre>

<h3 id="toc-keepuserin">사용자의 풀스크린 모드 환경 유지하기</h3>

<p>가끔은 풀스크린 API가 약간 까다로울 수도 있습니다. 브라우저 업체는 사용자가 풀스크린 페이지에 멈춰져 있게 만드는 것을 원하지 않으므로 그들이 가능한한 최대한 빨리 풀스크린 모드를 해제할 수 있는 메커니즘을 개발했습니다. 이 뜻은 여러분이 다수의 페이지를 붙여놓은 풀스크린 웹사이트를 개발할 수 없다는 뜻입니다. 왜냐하면</p>

<ul>
  <li>window.location = "http://example.com"의 사용을 통해 프로그램적으로 URL을 변경하면 풀스크린 모드가 해제됩니다.
    </li>
  <li>사용자가 페이지 안에서 외부 링크를 클릭하면 풀스크린 모드를 빠져나갑니다.
    </li>
  <li><pre class="inline">navigator.pushState</pre> API를 통해 URL을 변경하는 경우 또한 풀스크린 환경을 깨뜨릴 것입니다.
    </li>
</ul>

<p>만약 여러분이 사용자를 풀스크린 환경에서 머물게 하고 싶다면 다음과 같은 2가지 옵션이 있습니다.</p>

<ol>
  <li>설치 가능한 웹앱 메커니즘을 사용하여 풀스크린 모드를 진행</li>
  <li># Fragment를 사용하여 UI와 앱 상태를 관리</li>
</ol>

<p>#문법을 사용하여 URL을 갱신(window.location = "#somestate")하고 window.onhashchange 이벤트를 기다리고 있다가 어플리케이션 상태의 변화를 관리하기 위해 브라우저 자체의 히스토리 스택을 사용할 수 있으며 사용자가 그들의 뒤로가기 하드웨어 버튼을 사용할 수 있도록 하거나 간단하게 프로그래밍된 뒤로가기 버튼 환경을 다음과 같은 히스토리 API의 사용을 통해 제공할 수 있습니다.</p>

<pre class="prettyprint">window.history.go(-1)</pre>

<h3 id="toc-letuserchoose">풀스크린 모드로 전환될 때를 사용자가 선택하게 두세요</h3>
<p>웹사이트가 불필요한 무언가를 할 때만큼 사용자를 짜증나게 하는 것은 아무것도 없습니다. 사용자가 여러분의 사이트를 이용할 때 풀스크린 모드를 시도하거나 풀스크린을 사용하도록 하는 트릭을 사용하지 마시기 바랍니다.</p>

<p>첫번째 터치 이벤트를 가로채서 requestFullScreen를 실행하지 마시기 바랍니다.</p>
<ol>
  <li>짜증나는 일입니다.</li>
  <li>풀스크린 모드의 앱 실행 여부 결정을 위해 앞으로도 같은 위치에서 브라우저로 하여금 사용자에게 물어보도록 것입니다.</li>
</ol>

<figure>
<img src="/static/images/mobile/fullscreen/ffos.png" style="width:300px;">
<figcaption>Figure 3: 풀스크린 모드 액세스를 위한 파이어폭스OS의 질의.</figcaption>
</figure>

<p>만약 풀스크린모드로 앱을 실행하기를 원한다면 각 플랫폼에 대한 설치 환경의 사용에 대해 생각해보세요.</p>

<h3 id="toc-nospam">사용자에게 홈스크린의 앱 설치에 대한 스팸을 보내지 마세요.</h3>
<p>만약 설치 앱 매커니즘을 통해 풀스크린 환경을 제공할 계획이라면 다음과 같이 사용자를 배려해주시기 바랍니다.</p>
<ul>
  <li>신중해지세요. 그들이 앱을 설치할 수 있다는 것을 알려주기 위한 배너나 꼬리말(footer)을 이용하세요.</li>
  <li>프롬프트가 사라지면 다시 보여주지 마세요.</li>
  <li>사용자가 처음으로 방문하면 여러분의 서비스로 행복해지지 않고서는 앱을 설치하기를 원할 것 같지는 않습니다. 사이트에 대한 긍정적인 반응 후에 설치를 위한 질의를 하는 것을 고려해보세요.</li>
  <li>사용자가 사이트에 정기적으로 방문하고 그들이 앱을 설치하지 않았다면 미래에도 앱을 설치하기를 원할 것 같지는 않습니다.</li>
</ul>

<h2 id="conslusions">결론</h2>
<p>완전하게 표준화되고 구현된 API가 없음에도 불구하고 이 글에서 말하는 몇가지 가이드를 사용하여 클라이언트에 상관없이 사용자가 전체 화면의 장점을 가지는 환경을 손쉽게 구축할 수 있습니다.</p>

<blockquote class="commentary talkinghead talkinghead-pk">만약 풀스크린에 대한 좋은 패턴을 아신다면 코멘트를 달아서 우리가 세상에 알릴 수 있도록 해주시기 바랍니다. 만약 풀스크린에 있어 피해야 할 패턴을 아신다면 우리에게 알림으로써 수십만 웹사용자가 가질 불만의 회피를 위해 글을 업데이트할 수 있게 해주시기 바랍니다.
</blockquote>

{% endblock %}
